<?php
#### MODEL LIBRARY #############################################################
class ModelLibrary {
	
	private $data;
	private $table;
	private $hasMany = array();
	private $hasOne = array();
	private $belongsTo = array();
	private $belongsToMany = array();
	
	#### DATA ##################################################################
	public function data() { return $this->data; }

	#### SET TABLE #############################################################
	public function setTable($table = null) { $this->table = $table; }
	
	#### GET TABLE #############################################################
	public function getTable() { return $this->table; }

	#### HAS MANY ##############################################################
	public function hasMany($array) { $this->hasMany = $array; }

	#### HAS ONE ###############################################################
	public function hasOne($array) { $this->hasOne = $array; }

	#### BELONGS TO ############################################################
	public function belongsTo($array) { $this->belongsTo = $array; }

	#### BELONGS TO MANY #######################################################
	public function belongsToMany($array) { $this->belongsToMany = $array; }
	
	#### __GET #################################################################
	public function __get($name) {
		if ($this->data && array_key_exists($name, $this->data)) 
			return $this->data[$name];
		else if ($this->relationExists('hasMany', $name))
			return $this->getRelations('hasMany', $name);
		else if ($this->relationExists('hasOne', $name))
			return $this->getRelations('hasOne', $name);
		else if ($this->relationExists('belongsTo', $name))
			return $this->getRelations('belongsTo', $name);
		else if ($this->relationExists('belongsToMany', $name))
			return $this->getRelations('belongsToMany', $name);
	}

	#### __SET #################################################################
	public function __set($name, $value) { $this->data[$name] = $value; }	

	#### __ISSET ##############################################################
	public function __isset($name) { return isset($this->data[$name]); }

	#### CREATE ################################################################
	public function create($set = false) {
		if (!$set) $set = $this->data;
		db()->insert($this->getTable(), $set);
		db()->query() or db()->error();
		return db()->insertID();
	}
	
	#### READ ##################################################################
	public function read($id = false, $field = 'id') {
		if (!$id) $id = $this->id;
		if (!is_array($id)) {
			$id = db()->escapeString($id);
			$id = (is_numeric($id) ? $id : '"'.$id.'"');
		}
		db()->select()
			->from($this->getTable())
			->where((is_array($id) ? $id : $field.' = '.$id));
		db()->query() or db()->error();
		$this->data = db()->fetchAssoc();
		return $this;
	}

	#### UPDATE ################################################################
	public function update($id = false, $set = false, $field = 'id') {
		if (!$id) $id = $this->id;
		if (!$set) $set = $this->data;
		// unset($set[$field]); // Don't try to set ID field
		db()->update($this->getTable())
			->set($set)
			->where($field.' = "'.db()->escapeString($id).'"');
		db()->query() or db()->error();
	}
	
	#### DELETE ################################################################
	public function delete($id = false, $field = 'id', $kind = false) {
		if (!$id) $id = $this->id;
		if (!$kind) $kind = array('hasMany', 'hasOne');
		$this->forEachRelation('deleteRelations', $id, $kind);

		db()->delete($this->getTable())
			->where($field.' = "'.db()->escapeString($id).'"');
		db()->query() or db()->error();
	}

	#### FIND ##################################################################
	public function find($conditions = false, $limit = 0) {
		db()->select()
			->from($this->getTable())
			->where($conditions)
			->limit($limit);
		db()->query() or db()->error();
		return $this->resultArraytoObjectArray(db()->fetchResultArray(), $limit);
	}
	
	#### SELECT ################################################################
	public function select($columns = '*', $sql = false, $limit = 0) {
		db()->select($columns)
			->from($this->getTable())
			->addSQL(' '.$sql.' ')
			->limit($limit);
		db()->query() or db()->error();
		return $this->resultArraytoObjectArray(db()->fetchResultArray(), $limit);
	}
	
	#### SAVE ##################################################################
	public function save() {
		$object = $this->getObjectVars();
		if (isset($object->id)) $this->update($object->id, (array) $object);
		else return $this->create((array) $object);
	}
	
	#### VARS ##################################################################
	private function getObjectVars() {
		$object = get_object_vars($this); 
		return (object) $object;
	}
	
	#### RELATION EXISTS #######################################################
	private function relationExists($relation, $name) {
		if (array_key_exists($name, $this->$relation) || 
			in_array($name, $this->$relation)) return true;
		else return false;
	}
	
	#### GET RELATIONS #########################################################
	private function getRelations($relation, $name) {
		if (!isset($this->data['id'])) return array();
		$relationArray = $this->$relation;
		$field = (isset($relationArray[$name]) ? $relationArray[$name] : null);
		if ($relation == 'hasOne' || $relation == 'hasMany') {
			$key = ($field ? $field : 'pid');
			$value = $this->data['id'];
		} else {
			$key = 'id';
			$value = ($field ? $this->data[$field] : $this->data['pid']);
		}
		db()->select()
			->from($name)
			->where($key.' = "'.$value.'"');
		db()->query() or db()->error();

		if ($relation == 'hasOne' || $relation == 'belongsTo')
			return $this->arraytoObject(db()->fetchArray(), 1);
		else
			return $this->resultArraytoObjectArray(db()->fetchResultArray());
	}	

	#### FOR EACH RELATION #####################################################
	private function forEachRelation($method, $id, $kind = false) {
		
		if (!is_array($kind)) $kind = array($kind);
		if (!$kind) 
			$kind = array('hasMany', 'hasOne', 'belongsTo', 'belongsToMany');

		if ($this->hasMany && in_array('hasMany', $kind)) 
			foreach ($this->hasMany as $table => $key) {
				$this->$method($table, $key, $id);
		} 
		if ($this->hasOne && in_array('hasOne', $kind))
			foreach ($this->hasOne as $table => $key) {
				$this->$method($table, $key, $id);
		} 
		if ($this->belongsTo && in_array('belongsTo', $kind)) 
			foreach ($this->belongsTo as $table => $key) {
				$this->$method($table, $key, $id);
		} 
		if ($this->belongsToMany && in_array('belongsToMany', $kind)) 
			foreach ($this->belongsToMany as $table => $key) {
				$this->$method($table, $key, $id);
		}
	}
	
	#### DELETE RELATIONS ######################################################
	private function deleteRelations($table, $key, $id) {
		if (is_numeric($table)) {
			$table = $key;
			$key = 'pid';
		}
		db()->delete($table)
			->where($key.' = "'.db()->escapeString($id).'"');
		db()->query() or db()->error();
	}
	
	#### ARRAY TO OBJECT #######################################################
	private function arraytoObject($rows, $limit = false) {
		// Create ModelLibrary instance
		$object = clone $this;
		if ($rows) foreach ($rows as $key => $value) {
			$object->data[$key] = $value;
		}
		
		return $object;
	}
	
	#### RESULT ARRAY TO OBJECT ARRAY ##########################################
	private function resultArraytoObjectArray($rows, $limit = false) {
		// Create ModelLibrary instances for each row returned
		foreach ($rows as $row) {
			$object = clone $this;
			$object->data = $row;
			$objects[] = $object;
		}
		
		// Return an object not an array if we only want a single row
		if (isset($objects) && $limit == 1) $objects = $objects[0];

		// If there were no results return an empty ModelLibrary instance
		if (!isset($objects)) $objects = clone $this;

		return $objects;
	}
}
?>